// lib/services/ble/ble_device_service.dart
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:permission_handler/permission_handler.dart';

/// 协议数据包
class ProtocolPacket {
  final int head; // 0xAA / 0xAB
  final int id;
  final int d1;
  final int d2;
  final int d3;
  final int checksum;

  ProtocolPacket(this.head, this.id, this.d1, this.d2, this.d3, this.checksum);

  Uint8List toBytes() => Uint8List.fromList([head, id, d1, d2, d3, checksum]);

  static String hex2(List<int> bytes) =>
      bytes.map((e) => e.toRadixString(16).padLeft(2, '0').toUpperCase()).join(' ');
}

class BLEDeviceService {
  static final BLEDeviceService _i = BLEDeviceService._();
  factory BLEDeviceService() => _i;
  BLEDeviceService._();

  BluetoothDevice? connectedDevice;
  BluetoothCharacteristic? _notifyChar; // FFE1
  BluetoothCharacteristic? _writeChar;  // FFE2

  final _notifyCtrl = StreamController<List<int>>.broadcast();
  Stream<List<int>> get onDataRaw => _notifyCtrl.stream;

  final _packetCtrl = StreamController<ProtocolPacket>.broadcast();
  Stream<ProtocolPacket> get onPacket => _packetCtrl.stream;

  final _scanCtrl = StreamController<List<ScanResult>>.broadcast();
  Stream<List<ScanResult>> get scanStream => _scanCtrl.stream;

  // ======================================================
  // 扫描设备
  // ======================================================
  Future<void> startScan({int seconds = 15}) async {
    await _ensurePermissions();

    print('🟢 [BLE] >>> 开始扫描 $seconds 秒');
    final seen = <String>{};

    final sub = FlutterBluePlus.scanResults.listen((list) {
      _scanCtrl.add(list);

      for (final r in list) {
        final id = r.device.remoteId.str;
        if (!seen.contains(id)) {
          seen.add(id);
          print('📡 扫描到: ${r.device.platformName}  id=$id  RSSI=${r.rssi}');
        }
      }
    });

    await FlutterBluePlus.startScan(timeout: Duration(seconds: seconds));
    await Future.delayed(Duration(seconds: seconds));
    await FlutterBluePlus.stopScan();
    await sub.cancel();

    print('🛑 扫描结束，总共发现: ${seen.length}');
  }

  Future<void> stopScan() async {
    print('🛑 手动停止扫描');
    await FlutterBluePlus.stopScan();
  }

  // ======================================================
  // 连接
  // ======================================================
  Future<void> connect(String deviceId) async {
    await _ensurePermissions();

    final dev = BluetoothDevice(remoteId: DeviceIdentifier(deviceId));
    print('🔗 连接: $deviceId');
    await dev.connect(timeout: const Duration(seconds: 10));

    connectedDevice = dev;

    final services = await dev.discoverServices();
    final ffe0 = services.firstWhere(
          (s) => s.uuid.str.toUpperCase().endsWith('FFE0'),
      orElse: () => services.first,
    );

    for (final c in ffe0.characteristics) {
      final uuid = c.uuid.str.toUpperCase();
      if (uuid.endsWith('FFE1') && c.properties.notify) {
        _notifyChar = c;
      }
      if (uuid.endsWith('FFE2') &&
          (c.properties.write || c.properties.writeWithoutResponse)) {
        _writeChar = c;
      }
    }

    if (_notifyChar != null) {
      await _notifyChar!.setNotifyValue(true);
      _notifyChar!.onValueReceived.listen(_onNotifyData);
      print('🔔 已启用 notify');
    } else {
      print('⚠️ 未找到 notify 特征');
    }

    print('✍️ 写入特征: ${_writeChar?.uuid.str}');
  }

  Future<void> disconnect() async {
    if (connectedDevice != null) {
      print('🔌 断开连接');
      await connectedDevice!.disconnect();
    }
    connectedDevice = null;
    _notifyChar = null;
    _writeChar = null;
  }

  // ======================================================
  // 写入帧（通用）
  // ======================================================
  Uint8List buildFrame(int id, int d1, int d2, int d3) {
    final head = 0xAA;
    final sum = (head + id + d1 + d2 + d3) & 0xFF;
    final bytes = Uint8List.fromList([head, id, d1, d2, d3, sum]);
    print('➡️ [TX] ${ProtocolPacket.hex2(bytes)}');
    return bytes;
  }

  Future<void> sendFrame(
      int id, {
        int d1 = 0,
        int d2 = 0,
        int d3 = 0,
      }) async {
    if (_writeChar == null) {
      print('❌ 写入特征未准备好');
      return;
    }
    final f = buildFrame(id, d1, d2, d3);
    await _writeChar!.write(f, withoutResponse: false);
  }

  // ======================================================
  // 已有基础命令
  // ======================================================
  Future<void> cmdPowerOn()  => sendFrame(0x01, d1: 0x31);
  Future<void> cmdPowerOff() => sendFrame(0x01, d1: 0x30);

  Future<void> cmdQueryTempAndState() => sendFrame(0x02);

  // ======================================================
  // 🌡 摄氏设定温度（保持原 ID=0x22，但补齐 3 字节）
  // ======================================================
  Future<void> cmdSetTempC(int celsius) async {
    final c = celsius.clamp(25, 65);
    final s = c.toString().padLeft(3, '0');   // 变3位 ASCII
    await sendFrame(0x22,
        d1: s.codeUnitAt(0),
        d2: s.codeUnitAt(1),
        d3: s.codeUnitAt(2));
  }

  // ======================================================
  // 🌡 华氏设定温度（新的，实现 Fahrenheit）
  // ======================================================
  Future<void> cmdSetTempF(int fahrenheit) async {
    final f = fahrenheit.clamp(77, 149);
    final s = f.toString().padLeft(3, '0');   // 3位 ASCII
    await sendFrame(0x23,
        d1: s.codeUnitAt(0),
        d2: s.codeUnitAt(1),
        d3: s.codeUnitAt(2));
  }

  // ======================================================
  // 时间设定
  // ======================================================
  Future<void> cmdSetTimeMin(int minutes) async {
    final m = minutes.clamp(1, 60).toString().padLeft(2, '0');
    await sendFrame(0x25,
        d1: m.codeUnitAt(0),
        d2: m.codeUnitAt(1));
  }

  // ======================================================
// ⭐ 新增：负离子工作时间（ID = 0x10）
// ======================================================
  Future<void> cmdSetAnionTimeMin(int minutes) async {
    // 限制范围 0~30
    final m = minutes.clamp(0, 30);

    // 转成两位 ASCII（协议要求）
    final s = m.toString().padLeft(2, '0');  // "05" / "28" / "30"
    final d1 = s.codeUnitAt(0);  // 高位 ASCII
    final d2 = s.codeUnitAt(1);  // 低位 ASCII

    // 发送：0xAA + 0x10 + d1 + d2 + 0x00 + checksum
    await sendFrame(0x10, d1: d1, d2: d2, d3: 0x00);

    print("🕒 [BLE] 设置负离子工作时间: $m 分钟 (ASCII $s)");
  }



  int _b(bool on) => on ? 0x31 : 0x30;

  Future<void> cmdInnerLight(bool on) => sendFrame(0x03, d1: _b(on));
  Future<void> cmdQueryInnerLight() => sendFrame(0x04);

  Future<void> cmdInnerLightLevel(int lv) =>
      sendFrame(0x05, d1: 0x30 + lv.clamp(1, 8));

  Future<void> cmdOuterLight(bool on) => sendFrame(0x06, d1: _b(on));
  Future<void> cmdQueryOuterLight() => sendFrame(0x07);

  Future<void> cmdOuterLightLevel(int lv) =>
      sendFrame(0x08, d1: 0x30 + lv.clamp(1, 8));

  Future<void> cmdColorLight(bool on) => sendFrame(0x0A, d1: _b(on));
  Future<void> cmdQueryColorLight() => sendFrame(0x09);

  Future<void> cmdColorLightLevel(int lv) =>
      sendFrame(0x0B, d1: 0x30 + lv.clamp(1, 4));

  Future<void> cmdColorLightColor(int index) =>
      sendFrame(0x0C, d1: 0x32, d2: 0x30 + index.clamp(1, 12));

  Future<void> cmdColorModeFixed(int n) =>
      sendFrame(0x0D, d1: n.clamp(0, 6));

  Future<void> cmdOzone(bool on) => sendFrame(0x0E, d1: _b(on));
  Future<void> cmdAnion(bool on) => sendFrame(0x0F, d1: _b(on));

  Future<void> cmdPowerRatio(int mode) =>
      sendFrame(0x12, d1: 0x30 + mode.clamp(1, 3));

  Future<void> cmdRedLight(bool on) => sendFrame(0x13, d1: _b(on));
  Future<void> cmdSeatHeat(bool on) => sendFrame(0x14, d1: _b(on));
  Future<void> cmdFootHeat(bool on) => sendFrame(0x15, d1: _b(on));
  Future<void> cmdFan(bool on)  => sendFrame(0x16, d1: _b(on));

  Future<void> cmdQueryHeartRate() => sendFrame(0x11);

  // ======================================================
  // 查询设定温度（得到 0x24 / 0xA4）
  // ======================================================
  Future<void> cmdQueryTargetTemp() => sendFrame(0x24);

  Future<void> cmdQueryTargetTime()  => sendFrame(0x26);
  Future<void> cmdQueryRemainTime() => sendFrame(0x27);

  // ======================================================
  // 接收回包
  // ======================================================
  void _onNotifyData(List<int> data) {
    if (data.isEmpty) return;

    print('⬅️ [RX] ${ProtocolPacket.hex2(data)}');
    _notifyCtrl.add(List<int>.from(data));

    if (data.length >= 6) {
      final p = ProtocolPacket(data[0], data[1], data[2], data[3], data[4], data[5]);
      final calc = (p.head + p.id + p.d1 + p.d2 + p.d3) & 0xFF;

      if (calc != p.checksum) {
        print('⚠️ 校验失败');
      }

      _packetCtrl.add(p);
      _logParsed(p);
    }
  }

  void _logParsed(ProtocolPacket p) {
    if (p.head != 0xAB) return;

    switch (p.id) {
      case 0x01:
        print('🟢 [回包] 开关机: ${p.d1 == 0x31 ? "开" : "关"}');
        break;
      case 0x02:
        final s = String.fromCharCodes([p.d1, p.d2, p.d3].where((e) => e != 0));
        print('🌡 [回包] 实际温度：$s');
        break;
      case 0x22:
      case 0x23:
        final s = String.fromCharCodes([p.d1, p.d2, p.d3].where((e) => e != 0));
        print('🎯 [回包] 设定温度：$s');
        break;
      case 0x25:
        final s = String.fromCharCodes([p.d1, p.d2].where((e) => e != 0));
        print('⏱ [回包] 设定时间：$s min');
        break;
      default:
        print('ℹ️ 回包 id=0x${p.id.toRadixString(16)}');
    }
  }

  // ======================================================
  // 权限
  // ======================================================
  Future<void> _ensurePermissions() async {
    final scan = await Permission.bluetoothScan.request();
    final conn = await Permission.bluetoothConnect.request();
    final loc  = await Permission.locationWhenInUse.request();
    if (scan.isDenied || conn.isDenied || loc.isDenied) {
      throw Exception('蓝牙或定位权限未授予');
    }
    if (!(await FlutterBluePlus.isOn)) {
      await FlutterBluePlus.turnOn();
    }
  }

  void dispose() {
    _notifyCtrl.close();
    _packetCtrl.close();
    _scanCtrl.close();
  }
}
